/**
 * @file lora_port_tim.c
 * @brief 硬件定时器 TIM 封装API
 * @author wangh (wanghuan3037@fiberhome.com)
 * @version 1.0
 * @date 2020-06-05
 * @copyright Copyright (c) 2020  烽火通信
 ***************************************************************
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version  <th>Author  <th>Description
 * <tr><td>2020-10-23 <td>1.0      <td>wangh   <td>内容
 * </table>
 */ 
#include "stm32f10x.h"
#include <math.h>
#include "lora_port_tim.h"
#include "lora_port_timer.h"
#include "utilities.h"

#undef LOG_LEVEL_
#define LOG_LEVEL_ 	LOG_LVL_WARN	// LOG_LVL_WARN LOG_LVL_INFO LOG_LVL_DEBUG
#include "bsp_log.h"


#define HW_TIMER_TIME_BASE				1 	// 定时器tick的ms数

volatile uint32_t TimerTickCounter = 1;		// tick计数

static uint32_t TimerTickCounterContext = 0;

volatile uint32_t TimeoutCntValue = 0;



void TimerHwInit( void )
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	
	TIM_DeInit(TIM2);	// tick定时器
	TIM_TimeBaseStructure.TIM_Period = 7200;	// 1ms
	TIM_TimeBaseStructure.TIM_Prescaler = 9;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
 
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM2, ENABLE);


	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &NVIC_InitStructure );
}


void TimerHwDeInit( void )
{
	TIM_DeInit(TIM2);
}

// 最小超时时间处理(单位ms)
uint32_t TimerHwGetMinimumTimeout( void )
{
    return( ceil( 2 * HW_TIMER_TIME_BASE ) );	// 大于或者等于指定表达式的最小整数
	
}

// 开始超时计时(单位ms)
void TimerHwStart( uint32_t val )
{
	uint32_t timeoutTick = 0;
	
	TimerTickCounterContext = TimerHwGetTimerValue( );	// 起始计数器值 tick
	
	if(val < 1)
		timeoutTick = 1;
	else
		timeoutTick = val / HW_TIMER_TIME_BASE;
	
	if( timeoutTick <= (0xFFFFFFFF - TimerTickCounterContext) )
	{
		TimeoutCntValue = TimerTickCounterContext + timeoutTick;
	}
	else
	{
		TimeoutCntValue = timeoutTick - (0xFFFFFFFF - TimerTickCounterContext) + 1;
	}
	log_d("TimerTickCounterContext = %d, TimeoutCntValue = %d\r\n", TimerTickCounterContext, TimeoutCntValue);
}

// 硬件定时器停止
void TimerHwStop( void )
{
	TIM_ITConfig( TIM2, TIM_IT_Update, DISABLE );
    TIM_Cmd( TIM2, DISABLE );
	
}



// 获取已经过的时间
uint32_t TimerHwGetElapsedTime( void )
{
	uint32_t currentTime = TimerHwGetTime( );	// 当前时间
	uint32_t contextTime = TimerTickCounterContext * HW_TIMER_TIME_BASE;
	
	log_d("currentTime = %d, contextTime = %d\r\n", currentTime, contextTime);
	if( currentTime < contextTime )
    {
        return( currentTime + ( 0xFFFFFFFF - contextTime ) );
    }
    else
    {
        return( currentTime - contextTime );
    }
}

uint32_t TimerHwComputeElapsedTime( uint32_t savedTime )
{
    TimerTime_t currentTime = 0;

    if( savedTime == 0 )
    {
        return 0;
    }

    currentTime = TimerHwGetTime(  );

    if( currentTime < savedTime )
    { 
		// roll over of the counter
		log_d("currentTime = %d, savedTime = %d\r\n", currentTime, savedTime);
        return( currentTime + ( 0xFFFFFFFF - savedTime ) );
    }
    else
    {
		log_d("currentTime = %d, savedTime = %d\r\n", currentTime, savedTime);
        return( currentTime - savedTime );
    }
}



// 获取当前tick计数
uint32_t TimerHwGetTimerValue( void )
{
    CRITICAL_SECTION_BEGIN( );

    uint32_t val = TimerTickCounter;

    CRITICAL_SECTION_END( );

    return( val );
}

// 获取当前定时器 ms 单位时间值
uint32_t TimerHwGetTime( void )
{
	return TimerHwGetTimerValue( ) * HW_TIMER_TIME_BASE;
}




static void TimerIncrementTickCounter( void )
{
    CRITICAL_SECTION_BEGIN( );
	
	if( TimerTickCounter == 0xFFFFFFFF )
		TimerTickCounter = 1;
	else
		TimerTickCounter++;

    CRITICAL_SECTION_END( );
}

void TIM2_IRQHandler( void )
{
    if( TIM_GetITStatus( TIM2, TIM_IT_Update ) != RESET )
    {
        TimerIncrementTickCounter( );
        TIM_ClearITPendingBit( TIM2, TIM_IT_Update );
    
        if( TimerTickCounter == TimeoutCntValue )
        {
            TimerIrqHandler( );
        }
    }
}


void TimerHwEnterLowPowerStopMode( void )
{
//#ifndef USE_DEBUGGER
//    __WFI( );
//#endif
}





/*********** (C) COPYRIGHT 2020 FiberHome *****END OF FILE****/
